package com.zazworka.machinelearning;

import java.util.HashMap;

import weka.classifiers.Classifier;
import weka.core.converters.ConverterUtils.DataSource;
import weka.core.Instance;
import weka.core.Instances;

public class Main {

	public static HashMap<Integer,Integer> instanceError;
	
	public static void main(String[] args) throws Exception{
		
		instanceError = new HashMap<Integer, Integer>();
		
		String[] classifiers = {
				"weka.classifiers.bayes.BayesNet",
				"weka.classifiers.bayes.ComplementNaiveBayes",
				"weka.classifiers.bayes.DMNBtext",
				"weka.classifiers.bayes.NaiveBayes",
				//"weka.classifiers.bayes.NaiveBayesSimple",
				"weka.classifiers.functions.MultilayerPerceptron",
				"weka.classifiers.functions.Logistic",
				"weka.classifiers.functions.RBFNetwork",
				"weka.classifiers.functions.SimpleLogistic",
				"weka.classifiers.lazy.IB1",
				"weka.classifiers.lazy.IBk",
				"weka.classifiers.lazy.KStar",
				"weka.classifiers.lazy.LWL",
				"weka.classifiers.meta.AdaBoostM1",
				"weka.classifiers.meta.AttributeSelectedClassifier",
				"weka.classifiers.meta.Bagging",
				"weka.classifiers.meta.ClassificationViaClustering",
				"weka.classifiers.meta.ClassificationViaRegression",
				"weka.classifiers.meta.CVParameterSelection",
				"weka.classifiers.meta.Dagging",
				"weka.classifiers.meta.Decorate",
				"weka.classifiers.meta.END",
				"weka.classifiers.meta.FilteredClassifier",
				"weka.classifiers.meta.Grading",
				"weka.classifiers.meta.LogitBoost",
				"weka.classifiers.meta.MultiBoostAB",
				"weka.classifiers.meta.MultiClassClassifier",
				"weka.classifiers.meta.MultiScheme",
				"weka.classifiers.meta.OrdinalClassClassifier",
				"weka.classifiers.meta.RacedIncrementalLogitBoost",
				"weka.classifiers.meta.RandomCommittee",
				"weka.classifiers.meta.RandomSubSpace",
				"weka.classifiers.meta.RotationForest",
				"weka.classifiers.meta.Stacking",
				"weka.classifiers.meta.StackingC",
				"weka.classifiers.meta.Vote",
				"weka.classifiers.misc.HyperPipes",
				"weka.classifiers.misc.VFI",
				"weka.classifiers.rules.ConjunctiveRule",
				"weka.classifiers.rules.DecisionTable",
				"weka.classifiers.rules.DTNB",
				"weka.classifiers.rules.JRip",
				"weka.classifiers.rules.NNge",
				"weka.classifiers.rules.OneR",
				"weka.classifiers.rules.PART",
				"weka.classifiers.rules.Ridor",
				"weka.classifiers.rules.ZeroR",
				"weka.classifiers.trees.BFTree",
				"weka.classifiers.trees.DecisionStump",
				"weka.classifiers.trees.FT",
				"weka.classifiers.trees.J48",
				"weka.classifiers.trees.J48graft",
				"weka.classifiers.trees.LADTree",
				"weka.classifiers.trees.LMT",
				"weka.classifiers.trees.NBTree",
				"weka.classifiers.trees.RandomTree",
				"weka.classifiers.trees.REPTree",
				"weka.classifiers.trees.SimpleCart"};
		
		//read instance into WEKA format
		Instances instances = DataSource.read(args[0]);
		instances.setClassIndex(instances.numAttributes() -1);
		
		
		for(String classifier : classifiers){
			int error = doLeaveOneOutCrossValidation(classifier, instances);
			System.out.println(classifier+": "+error);
		}
		
		
		//print error per instance
		for(int i = 0; i < instances.numInstances(); i++){
			if(instanceError.containsKey(i)){
				System.out.println("Error for "+i+" : "+instanceError.get(i));
			}
			else{
				System.out.println("Error for "+i+" : 0");
			}
			
		}
		
		//attention! when deleting elements put them into decreasing order so the indexes of the previous elements do not change 
//		
//		instances.delete(27);
//		instances.delete(20);
//		instances.delete(17);
//		instances.delete(15);
//		instances.delete(10);
		
//		instances.delete(21);
//		instances.delete(17);
//		instances.delete(15);
		
//		instances.delete(27);
//		instances.delete(21);
//		instances.delete(17);
//		instances.delete(16);
//		instances.delete(15);
//		instances.delete(11);
//		instances.delete(8);
//		
//		instances.delete(27);
//		instances.delete(21);
//		instances.delete(20);
//		instances.delete(17);
//		instances.delete(16);
//		instances.delete(15);
//		instances.delete(11);
//		instances.delete(10);
//		instances.delete(8);
		
		for(String classifier : classifiers){
			int error = doLeaveOneOutCrossValidation(classifier, instances);
			System.out.println(classifier+": "+error);
		}
		
	}
	
	static private int doLeaveOneOutCrossValidation(String classifierName, Instances instances) throws Exception{
		
		String[] options = {""};
		Classifier classifier = Classifier.forName(classifierName, options);
		
		int error = 0;
		
		//building training sets, train, predict, compute error
		for(int i = 0; i < instances.numInstances(); i++){
			Instances trainingInstances =  new Instances(instances);
			trainingInstances.delete(i);
			Instance toClassify = instances.instance(i);
			classifier.buildClassifier(trainingInstances);
			double result = classifier.classifyInstance(toClassify);
			//System.out.println("predicted:"+result+"\t actual:"+toClassify.classValue());
			error += Math.abs(result-toClassify.classValue());
			increaseInstanceError(i,new Double(Math.abs(result-toClassify.classValue())).intValue());
		}
		
		return error;
	}
	
	static private void increaseInstanceError(int index, int error){
		if(instanceError.containsKey(index)){
			instanceError.put(index, instanceError.get(index)+error);
		}
		else{
			instanceError.put(index, error);
		}
	}
}
